package scaladuct.asm

import org.objectweb.asm.ClassReader
import java.lang.Class
import scaladuct.ContainsClassDefinition
import ClassStructureWriter._
import java.lang.reflect.Field

/**
 * <p>
 * Created by IntelliJ IDEA.
 * User: zslajchrt
 * Date: Aug 16, 2010
 * Time: 3:23:25 PM
 */

object Scala2JavaBean {

  def isConvertedScalaBean(bean: AnyRef): Boolean = {
    try {
      bean.getClass.getDeclaredField(Scala2JavaBeanClassWriter.SCALABEAN_FIELD)
      true
    }
    catch {
      case nsfe: NoSuchFieldException => false
    }
  }

  def getConvertedScalaBeanPropertyAnnotations(propertyName: String, bean: AnyRef): List[java.lang.annotation.Annotation] = {
    val scalaBeanField: Field = bean.getClass.getDeclaredField(Scala2JavaBeanClassWriter.SCALABEAN_FIELD)
    scalaBeanField.setAccessible(true)
    val scalaBean: AnyRef = scalaBeanField.get(bean)
    val propertyField: Field = scalaBean.getClass.getDeclaredField(propertyName)
    propertyField.getAnnotations().toList

  }

  def getConvertedScalaBeanPropertyAnnotation[A <: java.lang.annotation.Annotation](propertyName: String, bean: AnyRef, annotationClass: Class[A]): A = {
    val scalaBeanField: Field = bean.getClass.getDeclaredField(Scala2JavaBeanClassWriter.SCALABEAN_FIELD)
    scalaBeanField.setAccessible(true)
    val scalaBean: AnyRef = scalaBeanField.get(bean)
    val propertyField: Field = scalaBean.getClass.getDeclaredField(propertyName)
    propertyField.getAnnotation(annotationClass)
  }

  def apply(scalaBean: AnyRef): AnyRef = {
    val clazz: Class[_] = scalaBean.getClass
    val beanCl = if (scalaBean.isInstanceOf[ContainsClassDefinition]) {
      val byteCode = scalaBean.asInstanceOf[ContainsClassDefinition].classByteCode
      val classReader: ClassReader = new ClassReader(byteCode)
      val javaBeanClassWriter = new Scala2JavaBeanClassWriter
      classReader.accept(javaBeanClassWriter, 0)

      ClassStructureWriter(javaBeanClassWriter.writer.toByteArray)

      new javaBeanClassWriter.Scala2JavaBeanClassLoader

    } else {
      val classResourcePath = clazz.getName.replace('.', '/') + ".class"
      val scalaBeanClassResource = clazz.getClassLoader.getResource(classResourcePath)
      if (scalaBeanClassResource == null)
        throw new IllegalArgumentException("Cannot find the resource for class " + clazz.getName)
      val classReader: ClassReader = new ClassReader(scalaBeanClassResource.openStream)
      val javaBeanClassWriter = new Scala2JavaBeanClassWriter
      classReader.accept(javaBeanClassWriter, 0)

      //ClassStructureWriter(javaBeanClassWriter.writer.toByteArray)

      new javaBeanClassWriter.Scala2JavaBeanClassLoader
    }


    val cookieClass: Class[AnyRef] = beanCl.loadCookieClass.asInstanceOf[Class[AnyRef]]
    val cookie: AnyRef = cookieClass.getConstructor(clazz).newInstance(scalaBean)

    cookie
  }

}